﻿//=====================================================================================================
// LocalizationLibrary
// The Localization Library is a collection of reusable software components that provide 
// support for localization. This library enables you to localize WPF, Silverlight and WP7 applications.
// (http://localizationlibrary.codeplex.com)
//=====================================================================================================
// Author: Nicola Gallo (Website: www.nicola.gallo.name, Email: nicolagmt@hotmail.it) 
//=====================================================================================================
namespace ReflectionStudio.Core.Reflection
{
    //.NET References
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using ReflectionStudio.Core.Interface;
    using ReflectionStudio.LocalizationLibrary.Attributes;
    /// Implements a wrapper class of the class <see cref="PropertyInfo"/>.
    /// </summary>
    public class PropertyInfoRef
    {
        //Fields

        private Collection<Attribute> _customAttributes;
        private bool? _isLocalized = new Nullable<bool>();

        //Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="Type">Type.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown whether <paramref name="propertyInfo"/> parameter is null.
        /// </exception>
        public PropertyInfoRef(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
            {
                throw new ArgumentNullException("propertyInfo parameter shouldn't be null.");
            }
            this.PropertyInfo = propertyInfo;
        }

        //Properties

        /// <summary>
        /// Gets true whether the wrapperd <see cref="PropertyInfo"/> is localized, False otherwise.
        /// </summary>
        public bool IsLocalized 
        {
            get 
            {
                if (!this._isLocalized.HasValue)
                {
                    Attribute[] localizedAttributes = this.GetAttributes<LocalizeDynamicallyAttribute>();
                    if (localizedAttributes.Length > 0)
                    {
                        this._isLocalized = true;
                    }
                    else 
                    {
                        localizedAttributes = this.GetAttributes<LocalizeAttribute>();
                        if (localizedAttributes.Length > 0)
                        {
                            this._isLocalized = true;
                        }
                        else 
                        {
                            this._isLocalized = false;
                        }
                    }
                }
                return this._isLocalized.Value;
            }
        }

        /// <summary>
        /// Gets the resource bound at the property.
        /// </summary>
        public IResource Resource { get; set; }

        /// <summary>
        /// Gets wrapped <see cref="PropertyInfo"/>.
        /// </summary>
        public PropertyInfo PropertyInfo { get; private set; }

        /// <summary>
        /// Gets a dictionary that contains all the custom <see cref="Attribute"/>s loded.
        /// </summary>
        protected Collection<Attribute> CustomAttributes
        {
            get
            {
                if (this._customAttributes == null)
                {
                    this._customAttributes = new Collection<Attribute>();
                    object[] attribs = this.PropertyInfo.GetCustomAttributes(true);
                    if (attribs != null)
                    {
                        foreach (Attribute attrib in attribs)
                        {
                            this._customAttributes.Add(attrib);
                        }
                    }
                }
                return _customAttributes;
            }
        }

        //Methods

        /// <summary>
        /// Serves as a hash function for <see cref="PropertyInfoRef"/> type.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.PropertyInfo.GetHashCode();
        }

        /// <summary>
        /// Determines whether the specified <see cref="PropertyInfoRef"/> is equals to the current <see cref="PropertyInfoRef"/>.
        /// </summary>
        /// <param name="obj">Instance.</param>
        /// <returns>True whether the input instance is equals to the current instance otherwise False.</returns>
        public override bool Equals(object obj)
        {
            if (this == obj)
            {
                return true;
            }
            else if ((obj == null) || (obj.GetType() != this.GetType()))
            {
                return false;
            }
            PropertyInfoRef instance = obj as PropertyInfoRef;
            return instance.ToString().Equals(this.ToString());
        }

        /// <summary>
        /// Returns a <see cref="String"/> that represents the current <see cref="PropertyInfo"/>.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return String.Format("{0}:{1}", this.PropertyInfo.ReflectedType.FullName, this.PropertyInfo.Name);
        }

        /// <summary>
        /// Gets custom attributes defined in the <see cref="PropertyInfo"/>.
        /// </summary>
        /// <typeparam name="TAttribute">Represents the type of attributes searched.</typeparam>
        /// <returns>Array that contains the desired attributes.</returns>
        public Attribute[] GetAttributes<TAttribute>()
        {
            var queryAttribs = from customAttrib in this.CustomAttributes 
                               where ((typeof(TAttribute).IsAssignableFrom(customAttrib.GetType()))) 
                               select customAttrib;
            return queryAttribs.ToArray();
        }
    }
}